import json
import cv2
import sys
import datetime
from PyQt5.QtGui import QPixmap
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
import time
import re
from win32 import win32api, win32gui, win32print
from win32.lib import win32con

from win32.win32api import GetSystemMetrics

"""工具类"""


# 单天对象
class day_object():
    def __init__(self):  # 声明一下构成元素
        self.gregorian_calendar = None  # 阳历
        self.lunar_calendar = None  # 阴历
        self.week = None  # 星期
        self.solar_term = None  # 节气
        self.statutory_holidays = None  # 国内节日


# 月对象
class mouth_object():
    def __init__(self):
        self.msg = ""

    # 从日历文本中获取一个月的信息
    def get_msg(self, mouth_time):
        result = ""
        with open("../static/calendar.txt", "r") as f:
            while True:
                f1 = f.readline()
                if mouth_time in f1:  # 如果找到对应时间，则把这行加入列队
                    while True:  # 找到后向下找只到不是这个月的就结束
                        if mouth_time in f1:
                            result = result + f1
                            f1 = f.readline()
                        else:
                            break
                    break

        self.msg = result


# 教学周对象
class teaching_week_object():  # 教学周对象
    # 参数为位置、教学周字典
    def __init__(self, x, y, w, h, week_num):
        self.x = x
        self.y = y
        self.w = w
        self.h = h
        self.week_num = week_num

    # 生成一个复合标签, 参数1 窗口 参数2 是否高亮 参数3 是否显示
    def set_label(self, window, is_light, o):
        # 制作当周高亮

        pix = QPixmap('../static/img/红圈.png')  # 取图
        self.lb = QLabel(window)
        self.lb.setGeometry(self.x - 19, self.y, self.w, self.h)
        self.lb.setPixmap(pix)  # 把图片放入label
        self.lb.setScaledContents(True)  # 自适应QLabel大小
        if is_light == 1:
            self.lb.show()
        else:
            self.lb.hide()
        # 制作教学周label
        number = self.week_num
        # 显示数字
        self.lb1 = QLabel(window)
        self.lb1.setText(number)

        self.lb1.setGeometry(self.x -20, self.y, 60, 60)
        self.lb1.setAlignment(Qt.AlignCenter)

        font1 = QFont()  # 创建一个格式对象
        font1.setPixelSize(RATIO(40))  # 设置字体大小
        font1.setFamily("Arial")  # 设置字体
        font1.setBold(True)  # 加粗
        self.lb1.setFont(font1)  # 将lb1设置font1格式
        if o:
            self.lb1.show()
        else:
            self.lb1.hide()


# 日历对象
class calendar_object(QObject):
    signal = pyqtSignal(str)

    def __init__(self, x, y, w, h):
        super(calendar_object, self).__init__()
        self.x = x
        self.y = y
        self.w = w
        self.h = h

        self.day = None

    # 生成一个复合标签,0_x为控件是否透明,1为透明，0为不透明
    def set_label(self, window, o_1, o_2, o_3, o_4, o_5):
        # 制作当天日期高亮
        pix = QPixmap('../static/img/高亮背景.png')  # 取图
        self.lb = QLabel(window)
        self.lb.setGeometry(self.x + 2, self.y, self.w, self.h)
        self.lb.setPixmap(pix)  # 把图片self.放入label
        self.lb.setScaledContents(True)  # 自适应QLabel大小
        if o_1:
            self.lb.hide()

        # 制作日期显示label
        number = self.day.gregorian_calendar.split("日")[0].split("月")[1]  # 获取上面的数字
        if self.day.statutory_holidays != "无":  # 获取下面的显示的农历节气节日文本
            text = self.day.statutory_holidays
        elif self.day.solar_term != "无":
            text = self.day.solar_term
        else:
            if self.day.lunar_calendar.split("月")[1] == "初一":
                text = self.day.lunar_calendar.split("月")[0] + "月"
            else:
                text = self.day.lunar_calendar.split("月")[1]

        # 显示数字
        self.lb1 = QLabel(window)
        self.lb1.setText(number)
        self.lb1.setAlignment(Qt.AlignCenter)
        self.lb1.setGeometry(self.x + 7, self.y + 5, 50, 30)
        font1 = QFont()  # 创建一个格式对象
        font1.setPixelSize(RATIO(34))  # 设置字体大小
        font1.setFamily("NSimSun")  # 设置字体
        font1.setBold(True)  # 加粗
        self.lb1.setFont(font1)  # 将lb1设置font1格式
        if o_2:
            self.lb1.hide()
        # 显示农历
        self.lb2 = QLabel(window)
        self.lb2.setText(text)
        self.lb2.setAlignment(Qt.AlignCenter)
        self.lb2.setGeometry(self.x + 2, self.y + 27, self.w, 30)
        font2 = QFont()  # 创建一个格式对象
        font2.setPixelSize(RATIO(14))  # 设置字体大小
        font2.setFamily("NSimSun")  # 设置字体
        font2.setBold(True)  # 加粗
        self.lb2.setFont(font2)  # 将lb1设置font1格式
        if o_3:
            self.lb2.hide()
        # 显示安排
        pix = QPixmap('../static/img/日程标识.png')  # 取图
        self.lb3 = QLabel(window)
        self.lb3.setGeometry(self.x + 52, self.y, 10, 10)
        self.lb3.setPixmap(pix)  # 把图片放入label
        self.lb3.setScaledContents(True)  # 自适应QLabel大小
        if o_4:
            self.lb3.hide()

        # 点击按钮
        self.btn = QPushButton(window)
        self.btn.setGeometry(self.x + 2, self.y, self.w, self.h)
        self.btn.setStyleSheet("QPushButton{border-image: url(../static/img/透明.png)}"
                               "QPushButton:hover{border-image: url(../static/img/日期聚焦.png)}")
        self.btn.clicked.connect(self.click)

        if o_5:
            self.btn.hide()

    def click(self):
        self.signal.emit(
            str(self.x) + "," + str(self.y) + "," + str(self.w) + "," + self.day.gregorian_calendar.split("年")[0]
            + "," + self.day.gregorian_calendar.split("年")[1].split("月")[0] + "," +
            self.day.gregorian_calendar.split("年")[1].split("月")[1].split("日")[0])


# 事件对象
class event_object():

    def __init__(self, id=""):
        self.is_new = 1

        self.id = id
        self.title = ""
        self.start_time = ""
        self.end_time = ""
        self.event_type = ""
        self.content = ""
        self.images = ""
        self.videos = ""
        self.remind_msg = ""
        self.update()

    # 保存事件
    def save_event(self):
        event_dict = {}
        event_dict.update({"title": self.title, "start_time": self.start_time, "end_time": self.end_time,
                           "event_type": self.event_type, "content": self.content, "images": self.images,
                           "videos": self.videos, "remind_msg": self.remind_msg})
        with open('../event/event.json', 'rb') as f:  # 使用只读模型，并定义名称为f
            params = json.load(f)  # 加载json文件
            params.update({self.id: event_dict})
        with open('../event/event.json', 'w') as f1:  # 使用只读模型，并定义名称为f
            f1.write(json.dumps(params))

    # 如果文件中没有这个事件，则处理为新事件
    def update(self):
        with open('../event/event.json', 'rb') as f:  # 使用只读模型，并定义名称为f
            params = json.load(f)  # 加载json文件
            for key, e in params.items():
                if key == self.id:
                    self.is_new = 0
                    self.title = e["title"]
                    self.start_time = e["start_time"]
                    self.end_time = e["end_time"]
                    self.event_type = e["event_type"]
                    self.content = e["content"]
                    self.images = e["images"]
                    self.videos = e["videos"]
                    self.remind_msg = e["remind_msg"]

        if self.is_new:
            num = int(read_setting("事件数"))
            num = num + 1
            self.id = "s_" + str(num)
            update_setting("事件数", str(num))


"""工具函数"""


# 获取教学周字典,参数1 日期 参数2 持续周数
def get_teaching_week_dict(day, time):
    count = 1  # 教学周计数器
    dict = {}
    with open("../static/calendar.txt", "r") as f:
        f1 = f.readlines()
    for x in range(len(f1) - 1):
        if f1[x].split(":")[0] == day:  # 找到这一天
            i = x
            week_list = ["星期一", "星期二", "星期三", "星期四", "星期五", "星期六", "星期日"]
            for j in range(len(week_list)):  # 回溯到包含这一天周的星期一
                if week_list[j] == f1[i].split(":")[1].split(",")[1]:
                    i = i - j
            count_1 = 0  # 一周计数器
            list = []  # 暂时的容器
            for j in range(i, i + int(time) * 7 + 1):
                list.append(f1[j].split(":")[0])
                count_1 = count_1 + 1
                if count_1 == 7:
                    dict_1 = {str(count): list}
                    dict.update(dict_1)
                    count = count + 1
                    count_1 = 0
                    list = []
            break
    return dict


# 从数据文本中获取单天的信息
def get_day(gregorian_calendar):
    with open("../static/calendar.txt", "r") as f1:
        while True:
            s = f1.readline()
            if gregorian_calendar in s:  # 搜索文档，找到包含日期的那一行，转换为对象后返回
                day = day_object()
                day.gregorian_calendar = s.split(":")[0]
                day.lunar_calendar = s.split(":")[1].split(",")[0]
                day.week = s.split(":")[1].split(",")[1]
                day.solar_term = s.split(":")[1].split(",")[2]
                day.statutory_holidays = s.split(":")[1].split(",")[3].split("\n")[0]

                return day


# ps字体大小转换
def RATIO(num):
    result = int(num * 36 / 48)
    return num


# 农历转换
def change_lunar(day):
    if day.statutory_holidays != "无":
        return day.statutory_holidays
    elif day.solar_term != "无":
        return day.solar_term
    else:
        return day.lunar_calendar


# 获取星期对应的英文
def get_week_EN(week):
    if week == "星期一":
        return "Monday"
    elif week == "星期二":
        return "Tuesday"
    elif week == "星期三":
        return "Wednesday"
    elif week == "星期四":
        return "Thursday"
    elif week == "星期五":
        return "Friday"
    elif week == "星期六":
        return "Saturday"
    else:
        return "Sunday"


# 获取天气
def get_weather(city):
    import json
    import requests
    # api地址
    url = 'http://t.weather.sojson.com/api/weather/city/'

    # 读取json文件
    with open('../static/city.json', 'rb') as f:
        # 使用json模块的load方法加载json数据，返回一个字典
        cities = json.load(f)

        # 通过城市的中文获取城市代码
        city_code = cities.get(city)

        # 网络请求，传入请求api+城市代码
        response = requests.get(url + city_code)

        # 将数据以json形式返回，这个d就是返回的json数据
        d = response.json()

        # 当返回状态码为200，输出天气状况
        if (d['status'] == 200):
            temperature = d["data"]["wendu"]
            H_temperature = d["data"]["forecast"][0]["high"].split()[1][0:2]
            L_temperature = d["data"]["forecast"][0]["low"].split()[1][0:2]
            weather = d["data"]["forecast"][0]["type"]
            prompt = d["data"]["forecast"][0]["notice"]
            return temperature, H_temperature, L_temperature, weather, prompt


# 读取配置
def read_setting(key):
    with open('../static/setting.json', 'rb') as f:  # 使用只读模型，并定义名称为f
        params = json.load(f)  # 加载json文件
        result = params["%s" % key]
        return result


# 修改setting_json文件
def update_setting(key, set):
    with open('../static/setting.json', 'rb') as f:  # 使用只读模型，并定义名称为f
        params = json.load(f)  # 加载json文件
        params["%s" % key] = "%s" % set  # code字段对应的值修改为404
    with open('../static/setting.json', 'w') as f1:  # 使用只读模型，并定义名称为f
        f1.write(json.dumps(params))


# 日期格式检测(1901-2100)
def check_date_formate(s):
    res = re.search('^[0-9]{4}年[0-9]{1,2}月$', s)
    if res:
        y = int(s.split("年")[0])
        m = int(s.split("年")[1].split("月")[0])
        if 1901 <= y <= 2100 and 1<= m <=12:
            return True
        else:
            return False
    else:
        return False


# 获取对话框相对于主屏幕位置
def get_position(m_w, position):
    x = int(position.split(",")[0])
    y = int(position.split(",")[1])
    w = int(position.split(",")[2])
    return str(int(m_w.x() + x + w / 2 - 70)) + "," + str(m_w.y() + y - 120)


# 获取对话框相对于主屏幕位置
def get_position_state(w, type):
    y = 30 + w.y()
    if type == "1":
        x = 382 + w.x()
    else:
        x = 292 + w.x()
    return type + "," + str(x) + "," + str(y)


# 获取展示图片的位置大小信息
def get_img_x_y(w_1, h_1):
    if w_1 / h_1 > 164 / 126:
        w_2 = 164
        h_2 = int(h_1 * 164 / w_1)
        x = 426
        y = 116
    else:
        h_2 = 126
        w_2 = int(w_1 * 126 / h_1)
        y = 116
        x = int(508 - w_2 / 2)
    return x, y, w_2, h_2


# 获取展示视频的位置大小信息
def get_img_x_y_videos(w_1, h_1):
    if w_1 / h_1 > 164 / 126:
        w_2 = 164
        h_2 = int(h_1 * 164 / w_1)
        x = 426
        y = 281
    else:
        h_2 = 126
        w_2 = int(w_1 * 126 / h_1)
        y = 281
        x = int(508 - w_2 / 2)
    return x, y, w_2, h_2


# 取封面
def get_video_pic(name):
    cap = cv2.VideoCapture(name)
    cap.set(1, int(cap.get(7) / 2))  # 取它的中间帧
    rval, frame = cap.read()  # 如果rval为False表示这个视频有问题，为True则正常

    b = cvimg_to_qtimg(frame)
    return b


# cv图转qt图
def cvimg_to_qtimg(cvimg):
    height, width, depth = cvimg.shape
    cvimg = cv2.cvtColor(cvimg, cv2.COLOR_BGR2RGB)
    cvimg = QImage(cvimg.data, width, height, width * depth, QImage.Format_RGB888)
    return cvimg

# 查询这天是否有事件
def having_event(date):
    having_event = False  # 当天是否有事件

    with open("../event/event.json", "r") as f:
        events = json.load(f)
    for id, event in events.items():
        # 开始时间
        start_time = datetime.datetime(int(event["start_time"].split(",")[0]),
                                       int(event["start_time"].split(",")[1]),
                                       int(event["start_time"].split(",")[2]), 0, 0)
        # 结束时间
        end_time = datetime.datetime(int(event["end_time"].split(",")[0]), int(event["end_time"].split(",")[1]),
                                     int(event["end_time"].split(",")[2]), 23, 0)
        # 当前时间
        now_time = datetime.datetime(int(date.split(",")[0]), int(date.split(",")[1]),
                                     int(date.split(",")[2]), 12, 0)
        # 判断当前时间是否在范围时间内
        if start_time < now_time < end_time:
            having_event = True

    if having_event:
        return True

    # 设置添加日程按钮
    if having_event == False:
        return False

# 内容查询
def search_event(s):

    event_list = []

    with open("../event/event.json", "r") as f:
        events = json.load(f)
    for id, event in events.items():
        if s in event["title"] or s in event["content"]:
            event_list.append(id)

    return event_list

def get_real_resolution():
    """获取真实的分辨率"""
    hDC = win32gui.GetDC(0)
    # 横向分辨率
    w = win32print.GetDeviceCaps(hDC, win32con.DESKTOPHORZRES)
    # 纵向分辨率
    h = win32print.GetDeviceCaps(hDC, win32con.DESKTOPVERTRES)
    return w, h
